Activity是什么时候显示出来的?

概要

在Android开发中,Activity可谓是最重要之一的组件了。分析和熟悉Activity的启动流程,可帮助认识整个Android系统全貌。这里主要分析基于Android7.0从startActivity到Activity页面显示这一过程。

1.涉及主要类:

android.app.Instrumentation.java 
android.app.ActivityThread.java
android.app.ActivityManager.java
com.android.server.am.ActivityManagerService.java
com.android.internal.policy.PhoneWindon.java
com.android.internal.policy.DecorView.java
android.view.WindowManage.java
com.android.server.wm.WindowManagerService.java

2.流程图:


avtivity启动流程图.png

具体流程

1.Activity.startActivityForResult()
/**
 * @hide
 */
@Override
public void startActivityForResult(
        String who, Intent intent, int requestCode, @Nullable Bundle options) {
    ...
    Instrumentation.ActivityResult ar =
        mInstrumentation.execStartActivity(
            this, mMainThread.getApplicationThread(), mToken, who,
            intent, requestCode, options);
  ...
    }
    cancelInputsAndStartExitTransition(options);
}

首先我们看看这个mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, who,intent, requestCode, options)这个方法。其中第二个参数是ActivityThread类中的内部类ApplicationThread,这个是IBinder的代理类,用户接收ActivityMangageService的消息。

2.Instrumentation.execStartActivity()
 public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
      ...
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

这个方法主要通过IPC方式发送消息给AMS(指ActivityManageService.java(下同)),从而调用startActivity(),这里就涉及到AMS服务了,在这过程中会进行一系列的准备,其中保存判断被启动的的Activity所在的进程是否和当前Activity所在的进程一致,若不一致则会从zygote进程fork一个进程;还有比如Activity的启动方式的判断等。最终会通过Binder IPC调用ActivityThread.ApplicationThread中的scheduleLaunchActivity()方法

3.ActivityThread.ApplicationThread. scheduleLaunchActivity()

在这一步骤中会通过sendMessage(H.LAUNCH_ACTIVITY, r)发送消息给ActivityThread.H,从而调用handleLaunchActivity()方法;

4.ActivityThread.handleLaunchActivity()
  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    //省略部分代码
    Activity a = performLaunchActivity(r, customIntent);
    if (a != null) {
     //省略部分代码
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
      //省略部分代码
      }
}

这里主要看performLaunchActivity()这个方法,这个里面会创建Activity的实例,然后在调用Activity.attach()方法,之后调用Activity的一系列生命周期方法。

5.Activity.attach()
    final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback) {
    attachBaseContext(context);

    mFragments.attachHost(null /*parent*/);

    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) {
        mWindow.setUiOptions(info.uiOptions);
    }
    //省略部分代码
}

这个方法参数比较多,我们主要看下对应的Window的创建:通过代码我们可以看到只要调用attach方法就会创建一个对应的window,也就是说一个Activity对应一个window(window只有个实现类就是PhoneWindow)。PhoneWindow创建的同时又会创建DecorView(相当于是Activity的rootView)。

    public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks 

DecorView继承与FrameLayout,查看PhoneWindow.java源码你会发现会DecorView添加两个子View:R.id.title和com.android.internal.R.id.content。到这里就可以知道Activity和Window的关系了:


activity和window关系图.png
6.Activity.makeVisible()
void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

执行完attach之后紧接着会调用Activity中的相关生命周期方法onCreate()、onStart()和onResume()方法。之后就会执行上面的makeVisible()方法,这里才是真正的开始绘制显示Activity视图。在这个方法中会调用windowManage添加window,最终会通过ViewRootImpl.java这个类的setView(),然后在通过Binder IPC和WindowManageService通信最终完成window的添加。
这里有个问题:当我们每次去更新UI的时候都是通过ViewRootImpl去执行更新以及检查当前执行更新的线程。而ViewRootImpl的创建就是在执行wm.addView()的时候创建的。所以在ViewRootImpl没有创建之前是不会对线程进程检查及更新绘制UI的。

总结

通过对Activity的启动过程及视图的呈现分析,我们可以总结如下:

1、通过Binder IPC的方式和AMS通信完成Activity创建前的一系列准备。若要启动的这个Activity所在的进程没有启动,那么AMS会通过Socket发送消息给Zygote,Zygote会fork出应用程序进程,并且通过反射创建这个应用程序的ActivityThread,并且调用ActivityThread的main方法,此时这个应用程序就启动了;

2、在AMS完成准备工作之后又以IPC的方式发送lunchActivity消息,ActivityThread.ApplicationThreah 收到消息之后,又通过handler机制发送LAUNCH_ACTIVITY消息给ActivityThread.H;

3、之后通过Instrumentation.newActivity()完成Activity的创建;

( Activity activity = (Activity)clazz.newInstance())

4、在创建完Activity实例之后会调用Activity.acctch()方法完成window和DecorView的创建,最终通过WindowManage.addView()完成对window的添加。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • Zygote是什么?有什么作用? Android系统底层基于Linux Kernel, 当Kernel启动过程会创...
    Mr槑阅读 2,783评论 4 18
  • 前言 Launcher启动app launcher就是android桌面应用程序。也是操作系统启动有第一个app。...
    第八区阅读 969评论 0 2
  • 还真是的。养它足足考验了我的耐心,就连这几天做梦,都会梦见它煤球一样的脸,围着我的脚,绕来绕去。 十几天了,就算是...
    宁黛阅读 150评论 0 1
  • 长城是由传奇影业、环球影业、中影、乐视影业等影业公司联合出品。据透露,传奇影业负责剧本开发、制片、投资;环球影业负...
    北城巷陌阅读 658评论 2 2
  • 文||胡思入梦菲 我想有所房子,不是面朝大海,却是春暖花开。房子不需要很大,也不用建在繁华的都市。 它可以在宁静的...
    丁渔阅读 252评论 7 9